/*! ******************************************************************************
 *
 * Created on 2022年3月25日
 *
 * Copyright(c) YuZhou Big Data Laboratory CO.,Ltd, 2022.  All rights reserved.
 *
 *******************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 ******************************************************************************/

package org.yzbdl.lanius.core.metastore;

import java.lang.reflect.Field;
import java.util.Map;

import javax.persistence.Column;
import javax.persistence.Table;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Entity;

/**
 * @author hs@yzbdl.ac.cn
 *
 */
public class HutoolEntity extends Entity {
    private static final long serialVersionUID = 1L;

    public HutoolEntity() {
        super();
    }

    public HutoolEntity(String tableName, boolean caseInsensitive) {
        super(tableName, caseInsensitive);
    }

    public HutoolEntity(String tableName) {
        super(tableName);
    }

    public static <T> Entity parseEntity(T bean) {
        Table table = AnnotationUtil.getAnnotation(bean.getClass(), Table.class);
        return create(table.name()).parseBean(bean, true, true);
    }

    public static <T> Entity parseEntity(T bean, boolean isToUnderlineCase, boolean ignoreNullValue) {
        Table table = AnnotationUtil.getAnnotation(bean.getClass(), Table.class);
        return create(table.name()).parseBean(bean, isToUnderlineCase, ignoreNullValue);
    }

    /**
     * 创建Entity
     * 
     * @param tableName 表名
     * @return Entity
     */
    public static HutoolEntity create(String tableName) {
        return new HutoolEntity(tableName);
    }

    /**
     * 创建Entity
     * 
     * @param tableName 表名
     * @return Entity
     */
    public static <T> Entity create(T bean) {
        Table table = AnnotationUtil.getAnnotation(bean.getClass(), Table.class);
        return new Entity(table.name());
    }

    public static <T extends BaseEntity> Entity create(Class<T> clazz) {
        Table table = AnnotationUtil.getAnnotation(clazz, Table.class);
        return new Entity(table.name());
    }

    @Override
    public <T> Entity parseBean(T bean) {
        if (StrUtil.isBlank(this.getTableName())) {
            this.setTableName(StrUtil.lowerFirst(bean.getClass().getSimpleName()));
        }
        Assert.notNull(bean, "Bean class must be not null");
        Map<String, Object> map = BeanUtil.beanToMap(bean);

        for (java.util.Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Field field = ReflectUtil.getField(bean.getClass(), key);
            String dbField = AnnotationUtil.getAnnotationValue(field, Column.class, "name");
            if (StrUtil.isNotBlank(dbField)) {
                this.put(key, entry.getValue());
            }
        }
        return this;
    }

    @Override
    public <T> Entity parseBean(T bean, boolean isToUnderlineCase, boolean ignoreNullValue) {
        if (StrUtil.isBlank(this.getTableName())) {
            String simpleName = bean.getClass().getSimpleName();
            this.setTableName(isToUnderlineCase ? StrUtil.toUnderlineCase(simpleName) : StrUtil.lowerFirst(simpleName));
        }
        Assert.notNull(bean, "Bean class must be not null");

        Map<String, Object> map = BeanUtil.beanToMap(bean, false, ignoreNullValue);

        for (java.util.Map.Entry<String, Object> entry : map.entrySet()) {
            String entityFieldName = entry.getKey();
            Field field = ReflectUtil.getField(bean.getClass(), entityFieldName);
            String dbField = AnnotationUtil.getAnnotationValue(field, Column.class, "name");
            if (StrUtil.isNotBlank(dbField)) {
                this.put(isToUnderlineCase ? StrUtil.toUnderlineCase(entityFieldName) : entityFieldName,
                    entry.getValue());
            }
        }
        return this;
    }

}
